#include <math.h>
#include <stdio.h>
#include "port.h"
#include "sprite.h"
#include "player.h"
#include "background.h"
#include "physics.h"
#include "particle.h"
#include "databank.h"
#include "weapon.h"

int NUMBER_OF_PLAYERS = 2;
int PLAYER_SPRITE_WIDTH = 38; // where to get this?
double PLAYER_DIRECTION = 128;
double PLAYER_POS_X;
double PLAYER_POS_Y;

Background* DataBank::getBackground() {
    return background;
}

PhysicsModule* DataBank::getPhysicsModule() {
    return physics;;
}

/** Returns player of the given ID */
Player* DataBank::getPlayer(int id) {
    return players[id];
}

/** returns pointer to the configurations */
Config* DataBank::getconfig() {
    return &configs;
}

void DataBank::saveconfig() {
	char cdir[1024] = "";
	get_executable_name(cdir,1024);
	replace_filename(cdir,cdir, "", 1024);
	strcat(cdir,"config.cfg");
	
	set_config_file(cdir);
	
	printf("Saving..\n");
	
	set_config_int("General", "blurParticles", configs.blurParticles);
	set_config_int("General", "whiteParticles", configs.whiteParticles);
	set_config_int("General", "optimizePhysics", configs.optimizePhysics);
	
	set_config_int("General", "physicsResolution", configs.physPartitionRes);
	set_config_float("General", "gravitationalConstant", configs.gravitationalConstant);
	
	set_config_int("General", "playerHealth", configs.playerHealth);
	set_config_int("General", "numPlayers", configs.numPlayers);
	
	flush_config_file();
}

void DataBank::loadconfig() {
	char cdir[1024] = "";
	get_executable_name(cdir,1024);
	replace_filename(cdir,cdir, "", 1024);
	strcat(cdir,"config.cfg");
	
	set_config_file(cdir);
	
	printf("Loading..\n");
	
	configs.blurParticles = get_config_int("General", "blurParticles", 0);
	configs.whiteParticles = get_config_int("General", "whiteParticles", 0);
	configs.optimizePhysics = get_config_int("General", "optimizePhysics", 0);
	
	configs.physPartitionRes = get_config_int("General", "physicsResolution", 24);
	configs.gravitationalConstant = get_config_float("General", "gravitationalConstant", 30.0);
	
	configs.playerHealth = get_config_int("General", "playerHealth", 100);
	configs.numPlayers = get_config_int("General", "numPlayers", 2);
}


int DataBank::getPlayerAlive()
{
	int count = 0;
	for(unsigned int i=0;i<players.size(); i++) {
		if(players[i]->alive()) count++;
	}
	
	return count;
}

/** fills the initial data in the structure.
 *    Could posibly use a filename as a parameter later. */
void DataBank::readData() {
	sprites = new Sprite;
	
	sprites->load_sprites();
}


void DataBank::init(void)
{	
	// Setup some random configuration
	//configs.numPlayers = NUMBER_OF_PLAYERS;
	configs.screenWidth = SCREEN_W;
	configs.screenHeight = SCREEN_H-64; // To account for the interface
	configs.numPlanets = 6;
	PLAYER_POS_X = 75;
	PLAYER_POS_Y = SCREEN_H / 2;
	
	// Load configuration
	loadconfig();

	// Setup the background
	background = new Background(this);
	background->init();
	
	// Setup the physics system
	physics = new PhysicsModule(this);

}

void DataBank::newGame(int plc, GameType gt)
{
	// Create background
	if(gt == GAME_DEMO) { // A demo game will always use 6 planets
		int tmp = configs.numPlanets;
		configs.numPlanets = 6;
		background->generateMap();
		background->newGame();
		configs.numPlanets = tmp;
	}else background->newGame();
	
	// Player position table
	int pos[][2] =
		{ {PLAYER_POS_X,			PLAYER_POS_Y},
		  {SCREEN_W-PLAYER_POS_X,	PLAYER_POS_Y},
		  {SCREEN_W/2,				PLAYER_POS_X},
		  {SCREEN_W/2,				SCREEN_H-64-PLAYER_POS_X}
		};
	int dir[] =
		{ PLAYER_DIRECTION,
		  PLAYER_DIRECTION*2.0,
		  PLAYER_DIRECTION*3.0/2.0,
		  PLAYER_DIRECTION/2.0
		};
	
	int colors[] = {makecol(255,0,0), makecol(0,0,255), makecol(0,255,0), makecol(255,255,0) };
	
	// Setup players
    
    for (int i = 0; i < plc; i++) {
        Player* p = new Player(this);
        p->setType(HUMAN_PLAYER);
        //p->setPos(PLAYER_POS_X + ((SCREEN_W - PLAYER_POS_X * 2) * i)
        //        - PLAYER_SPRITE_WIDTH / 2, PLAYER_POS_Y);
        p->setPos(pos[i][0], pos[i][1]);
        p->setDir(dir[i]);
        p->setHP(configs.playerHealth);
        
        // Give weapons to the player
        p->giveWeapon(new Weapon(this, WEAPON_GUN));
        p->giveWeapon(new Weapon(this, WEAPON_LASER));
        p->giveWeapon(new Weapon(this, WEAPON_BADGER));
        p->giveWeapon(new Weapon(this, WEAPON_CARPET));
        p->giveWeapon(new Weapon(this, WEAPON_PLANETC));
        p->giveWeapon(new Weapon(this, WEAPON_CLUSTER));
        p->giveWeapon(new Weapon(this, WEAPON_PANZERSCHRECK));
        p->giveWeapon(new Weapon(this, WEAPON_BIGBANG));
        
        p->setColor(colors[i]);
        p->setup();
        
        players.push_back(p);
    }

}

void DataBank::clear(void)
{
	// Free player memory
	for(unsigned int i=0;i<players.size(); i++)
	{ delete players[i]; }
	
	// Free all shots
	for(std::list<Shot *>::iterator i = shots.begin(); i != shots.end(); i++)
	{ delete *i; }
	
	for(std::list<Particle *>::iterator i = parts.begin(); i != parts.end(); i++)
	{ delete *i; }
	
	for(std::vector<Weapon *>::iterator i = weapons.begin(); i != weapons.end(); i++)
	{ delete *i; }
	
	weapons.clear();
	parts.clear();
	shots.clear();
	players.clear();
	
	// Ask background and physics to clean themselves
	background->clear();
	physics->clear();
}

/** Don't wanna! */
Particle *DataBank::makeParticle(double *pos, double *vel, int color)
{
	Particle *tmp = new Particle(physics, color, pos, vel);
	parts.push_back(tmp);
	return tmp;
}

void DataBank::cleanParticles(void)
{
	std::list<Particle*>::iterator i;
	
	// List of particles to kill
	std::list<std::list<Particle*>::iterator> kills;
	std::list<std::list<Particle*>::iterator>::iterator scythe;
	
	for(i=parts.begin(); i != parts.end(); i++) {
		if((*i)->killMe) {
			kills.push_back(i);
		}
	}
	
	for(scythe = kills.begin(); scythe != kills.end(); scythe++) {
			delete(**scythe);
			parts.erase(*scythe);
	}
	kills.clear();
}


Shot *DataBank::makeShot(Shot *type)
{
	shots.push_back(type);
	return type;
}

void DataBank::cleanShots(void)
{
	std::list<Shot*>::iterator i;
	
	// List of shotsto kill
	std::list<std::list<Shot*>::iterator> kills;
	std::list<std::list<Shot*>::iterator>::iterator scythe;
	
	for(i=shots.begin(); i != shots.end(); i++) {
		if((*i)->killMe) {
			kills.push_back(i);
		}
	}
	
	for(scythe = kills.begin(); scythe != kills.end(); scythe++) {
		delete(**scythe);
		shots.erase(*scythe);
	}
	kills.clear();
}

void DataBank::interactShots(Player *pl)
{
    std::list<Shot*>::iterator i;
    for(i=shots.begin(); i != shots.end(); i++) {
        (*i)->doInteraction( (*i), pl);
    }
}
